/* Copyright (c) 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.orkut.client.api.samples.greetings.client.selector;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.orkut.client.api.samples.greetings.client.GreetingsClientBundle;
import com.google.orkut.client.api.samples.greetings.client.GreetingsCssResource;

/**
 * A SearchBox with a prompt. It calls the callbacks in
 * {@link SearchBoxUserInputCallback} when the search string is updated
 * or enter key is pressed.
 *
 * @author Shishir Birmiwal
 */
public class SearchBox extends Composite implements Focusable {
  private static final int ENTER_CHAR = 13;
  private static final int ESCAPE_CHAR = 27;
  private static SearchBoxUiBinder uiBinder = GWT
      .create(SearchBoxUiBinder.class);

  interface SearchBoxUiBinder extends UiBinder<Widget, SearchBox> {
  }

  public static interface SearchBoxUserInputCallback {
    void searchStringUpdated(String searchString);
    void enterPressed(String searchString);
  }

  @UiField
  TextBox inputBox;
  private String promptText = "";
  private boolean promptDisplayed;
  private final GreetingsCssResource css;
  private SearchBoxUserInputCallback cb;

  @Inject
  public SearchBox(GreetingsClientBundle cb) {
    css = cb.css();
    initWidget(uiBinder.createAndBindUi(this));
  }

  public void setCallback(SearchBoxUserInputCallback cb) {
    this.cb = cb;
  }

  public void setPromptText(String promptText) {
    this.promptText = promptText;
    if (!promptDisplayed && inputBox.getText().length() > 0) {
      return;
    }
    showPrompt();
  }

  public void resetPrompt() {
    inputBox.setText("");
    if (cb != null) {
      cb.searchStringUpdated("");
    }
  }

  @UiHandler("inputBox")
  protected void onBlur(BlurEvent e) {
    if (!inputBox.getText().trim().isEmpty()) {
      return;
    }
    showPrompt();
  }

  @UiHandler("inputBox")
  protected void onFocus(FocusEvent e) {
    if (!promptDisplayed) {
      return;
    }
    hidePrompt();
  }

  @UiHandler("inputBox")
  protected void onKeyUp(KeyUpEvent e) {
    int keyCode = e.getNativeKeyCode();
    if (keyCode == ENTER_CHAR) {
      if (cb != null) {
        cb.enterPressed(inputBox.getText());
        inputBox.setText("");
        cb.searchStringUpdated("");
      }
    } else {
      if (keyCode == ESCAPE_CHAR) {
        inputBox.setText("");
      }
      if (cb != null) {
        cb.searchStringUpdated(inputBox.getText());
      }
    }
  }

  private void showPrompt() {
    promptDisplayed = true;
    inputBox.setText(promptText);
    inputBox.setStyleName(css.searchBoxInputGrayed());
  }

  private void hidePrompt() {
    promptDisplayed = false;
    inputBox.setText("");
    inputBox.setStyleName(css.searchBoxInput());
  }

  @Override
  public int getTabIndex() {
    return inputBox.getTabIndex();
  }

  @Override
  public void setAccessKey(char arg0) {
    inputBox.setAccessKey(arg0);
  }

  @Override
  public void setFocus(boolean arg0) {
    inputBox.setFocus(arg0);
  }

  @Override
  public void setTabIndex(int arg0) {
    inputBox.setTabIndex(arg0);
  }
}
